package top.maof.book.aspect;

import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import top.maof.book.annotation.Hot;
import top.maof.book.map.BookMap;
import top.maof.book.model.Book;
import top.maof.book.rank.*;
import top.maof.book.rank.book.*;
import top.maof.book.service.BookService;
import top.maof.book.type.HotType;
import top.maof.book.utils.JWTUtils;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

@ApiModel("热点数据缓存")
@Aspect
@Component
@Slf4j
public class HotAspect {

    @Autowired
    ClickHotRank clickHotRank;

    @Autowired
    CollectionHotRank collectionHotRank;

    @Autowired
    LikesHotRank likesHotRank;


    @Autowired
    BookService bookService;


    @Autowired
    BookHandleRank bookHandleRank;

    @Autowired
    ClickBookHandleRank clickBookHandleRank;

    @Autowired
    LikesBookHandleRank likesBookHandleRank;

    @Autowired
    CollectionBookHandleRank collectionBookHandleRank;


    @Pointcut("@annotation(top.maof.book.annotation.Hot)")
    public void hot() {
    }


    // 处理表
    public Map<HotType, KeepRank> handleMap = new HashMap<>();


    @After("hot()")
    public void after(JoinPoint joinPoint) throws Throwable {
        log.info("HotAspect rank 执行...");

        //获取连接点的方法签名对象
        Signature signature = joinPoint.getSignature();

        //获取方法
        Method method = ((MethodSignature) signature).getMethod();

        // 获取注解
        Hot hot = method.getAnnotation(Hot.class);

        if (hot != null) {

            // 设置解析上下文(有哪些占位符，以及每种占位符的值)
            EvaluationContext context = new StandardEvaluationContext();

            //获取运行时参数的名称
            DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
            String[] parameterNames = discoverer.getParameterNames(method);
            //获取参数值
            Object[] parameterValues = joinPoint.getArgs();
            for (int i = 0; i < parameterNames.length; i++) {
                context.setVariable(parameterNames[i], parameterValues[i]);
            }

            // 创建解析器
            SpelExpressionParser parser = new SpelExpressionParser();
            // 获取表达式
            Expression expression = parser.parseExpression(hot.value());
            //解析,获取替换后的结果
            String bookId = expression.getValue(context).toString();

            Book book = bookService.find(Integer.parseInt(bookId));

            HandleChain<BookHo> chain = new HandleChain();

            chain.put(bookHandleRank);
            chain.put(collectionBookHandleRank, clickBookHandleRank, likesBookHandleRank);

            //原始的HTTP请求和响应的信息
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            String token = request.getHeader("token");

            Integer userId = null;

            String ip = request.getRemoteHost();

            if (token != null && JWTUtils.checkToken(token)) {
                userId = JWTUtils.getUserId(token);
            }

            if ("add".equals(hot.keepType())) {
                chain.add(BookMap.INSTANCE.toBookHo(book, hot.type(), userId, ip), chain);
            } else {
                chain.sub(BookMap.INSTANCE.toBookHo(book, hot.type(), userId, ip), chain);
            }
        }
    }
}
